package api

import (
	"api/global"
	"api/pkg"
	"api/request"
	"context"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
	"github.com/google/uuid"
	"net/http"
	"time"
)

func OrderAdd(c *gin.Context) {
	var form request.Order
	if err := c.ShouldBind(&form); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// 1. 定义锁的key（针对当前商品的全局锁）
	//lockKey := fmt.Sprintf("lock:shop:%d", form.ShopId)
	//// 定义用户订单的key（判断重复下单）
	//uuids := uuid.New().String()
	////userOrderKey := fmt.Sprintf("orderSn:%s", uuids)
	//// 定义库存的key
	//stockKey := fmt.Sprintf("shopId:%d", form.ShopId)

	//// 2. 先检查是否重复下单（这一步不需要锁，属于用户维度的判断）
	//result, err := global.Rdb.Get(context.Background(), userOrderKey).Result()
	//if err != nil && err != redis.Nil { // 注意区分"键不存在"和"查询错误"
	//	c.JSON(http.StatusInternalServerError, gin.H{
	//		"message": "Redis中用户订单查询失败：" + err.Error(),
	//		"code":    "500",
	//		"data":    nil,
	//	})
	//	return
	//}
	//if result != "" {
	//	c.JSON(http.StatusBadRequest, gin.H{
	//		"message": "不能重复下单",
	//		"code":    "400",
	//		"data":    nil,
	//	})
	//	return
	//}

	// 3. 生成唯一标识（用于释放锁时验证）
	//lockValue := uuid.New().String() // 需要引入uuid库
	//// 尝试获取锁，设置过期时间防止死锁（例如10秒，需大于业务执行时间）
	//lockAcquired, err := global.Rdb.SetNX(
	//	context.Background(),
	//	lockKey,
	//	lockValue,
	//	10*time.Second,
	//).Result()
	//if err != nil || !lockAcquired {
	//	c.JSON(http.StatusTooManyRequests, gin.H{
	//		"message": "抢购太火爆，请稍后再试",
	//		"code":    "429",
	//		"data":    nil,
	//	})
	//	return
	//}
	// 确保锁最终会释放
	//defer func() {
	//	// 使用Lua脚本原子性释放锁（防止释放别人的锁）
	//	script := `
	//        if redis.call('GET', KEYS[1]) == ARGV[1] then
	//            return redis.call('DEL', KEYS[1])
	//        else
	//            return 0
	//        end
	//    `
	//	global.Rdb.Eval(context.Background(), script, []string{lockKey}, lockValue)
	//}()

	// 4. 加锁后再检查库存并扣减（核心竞争区）
	//length, err := global.Rdb.LLen(context.Background(), stockKey).Result()
	//if err != nil {
	//	c.JSON(http.StatusInternalServerError, gin.H{
	//		"message": "查看库存失败：" + err.Error(),
	//		"code":    "500",
	//		"data":    nil,
	//	})
	//	return
	//}
	//if length <= 0 {
	//	c.JSON(http.StatusBadRequest, gin.H{
	//		"message": "暂无库存",
	//		"code":    "400",
	//		"data":    nil,
	//	})
	//	return
	//}
	//
	//// 5. 扣减库存
	//stock, err := global.Rdb.RPop(context.Background(), stockKey).Result()
	//if err == redis.Nil || stock == "" {
	//	c.JSON(http.StatusBadRequest, gin.H{"message": "暂无库存"})
	//	return
	//}

	//// 订单生成失败 归还扣减库存
	//orderNumber := true
	//defer func() {
	//	if orderNumber {
	//		_, err = global.Rdb.LPush(context.Background(), stockKey, stock).Result()
	//		if err != nil {
	//			return
	//		}
	//
	//	}
	//}()

	// 6. 生成订单（此时已成功扣减库存，可安全创建订单）
	//order := map[string]interface{}{
	//	"orderSn": uuids,
	//	"shopId":  form.ShopId,
	//	"userId":  form.UserId,
	//	"stock":   stock,
	//}
	//marshal, err := json.Marshal(&order)
	//if err != nil {
	//	c.JSON(http.StatusInternalServerError, gin.H{
	//		"message": "订单序列化失败：" + err.Error(),
	//		"code":    "500",
	//	})
	//	return
	//}
	// 存储用户订单（防止重复下单）
	//err = global.Rdb.Set(context.Background(), userOrderKey, marshal, time.Minute*25).Err()
	//if err != nil {
	//	c.JSON(http.StatusInternalServerError, gin.H{
	//		"message": "redis:订单生成失败" + err.Error(),
	//		"code":    "500",
	//	})
	//	return
	//}

	// 回滚库存
	//orderNumber = false

	//支付宝沙箱支付
	//pay, err := pkg.OrderPay()
	//if err != nil {
	//	return
	//}
	//
	//c.JSON(http.StatusOK, gin.H{
	//	"message": "下单成功",
	//	"code":    "200",
	//	"data": map[string]interface{}{
	//		"order": order,
	//		"pay":   pay, // 支付链接
	//	},
	//})

	// 第二方案 优化
	//使用rabbitmq

	lockKey := fmt.Sprintf("lock:shop:%d", form.ShopId)

	// 定义库存的key
	stockKey := fmt.Sprintf("shopId:%d", form.ShopId)
	// 用户-商品去重key
	userOrderKey := fmt.Sprintf("user:order:%d:%d", form.UserId, form.ShopId)

	// 唯一订单号
	orderSn := uuid.New().String()

	exists, err := global.Rdb.Exists(context.Background(), userOrderKey).Result()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"message": "系统错误"})
		return
	}
	if exists > 0 {
		c.JSON(http.StatusBadRequest, gin.H{"message": "不能重复下单"})
		return
	}
	//  Redis锁
	lockAcquired, err := global.Rdb.SetNX(context.Background(), lockKey, orderSn, time.Second*10).Result()
	if err != nil {
		return
	}
	if err != nil || !lockAcquired {
		c.JSON(http.StatusTooManyRequests, gin.H{
			"message": "抢购太火爆，请稍后再试",
			"code":    "429",
			"data":    nil,
		})
		return
	}

	//确保锁最终会释放
	defer func() {
		// Lua脚本：只有锁的值等于orderSn时才释放（防止释放其他请求的锁）
		script := `
            if redis.call('GET', KEYS[1]) == ARGV[1] then
                return redis.call('DEL', KEYS[1])
            else
                return 0
            end
        `
		global.Rdb.Eval(context.Background(), script, []string{lockKey}, orderSn)
	}()

	// 加锁后再检查库存并扣减（核心竞争区）
	stock, err := global.Rdb.RPop(context.Background(), stockKey).Result()
	if err == redis.Nil || stock == "" {
		c.JSON(http.StatusBadRequest, gin.H{"message": "暂无库存"})
		return
	}

	// 订单信息
	order := map[string]interface{}{
		"orderSn": orderSn,
		"shopId":  form.ShopId,
		"userId":  form.UserId,
		"number":  1,
	}
	marshal, err := json.Marshal(&order)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"message": "订单序列化失败：" + err.Error(),
			"code":    "500",
			"data":    nil,
		})
		return
	}

	rabbitmq := pkg.NewRabbitMQSimple("shop")
	rabbitmq.PublishSimple(string(marshal))

	// 记录用户已下单（去重）
	global.Rdb.Set(context.Background(), userOrderKey, orderSn, 24*time.Hour)

	//订单测试
	pay, err := pkg.OrderPay()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"message": "支付链接生成失败",
			"code":    "500",
			"data":    nil,
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"message": "订单生成成功，正在处理中",
		"code":    "200",
		"orderSn": orderSn,
		"data":    pay,
	})
}
